package org.linlinjava.litemall.wx.web;

import com.github.pagehelper.PageInfo;
import org.apache.commons.lang.StringUtils;
import org.linlinjava.litemall.core.systemConfig.SystemConfig;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.SortUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author All
 * @date 1.1
 */
@RestController
@RequestMapping("/wx/goods")
public class WxGoodsController {

	private LitemallGoodsService goodsService;

	private LitemallProductService productService;

	private LitemallIssueService goodsIssueService;

	private LitemallGoodsAttributeService goodsAttributeService;

	private LitemallCommentService commentService;

	private LitemallUserService userService;

	private LitemallCollectService collectService;

	private LitemallFootprintService footprintService;

	private LitemallCategoryService categoryService;

	private LitemallSearchHistoryService searchHistoryService;

	private LitemallGoodsSpecificationService goodsSpecificationService;

	private LitemallAdService litemallAdService;
	public WxGoodsController(
		LitemallGoodsService goodsService,
		LitemallProductService productService,
		LitemallIssueService goodsIssueService,
		LitemallGoodsAttributeService goodsAttributeService,
		LitemallCommentService commentService,
		LitemallUserService userService,
		LitemallCollectService collectService,
		LitemallFootprintService footprintService,
		LitemallCategoryService categoryService,
		LitemallSearchHistoryService searchHistoryService,
		LitemallAdService litemallAdService,
		LitemallGoodsSpecificationService goodsSpecificationService) {
		this.goodsService = goodsService;
		this.productService = productService;
		this.goodsIssueService = goodsIssueService;
		this.goodsAttributeService = goodsAttributeService;
		this.commentService = commentService;
		this.userService = userService;
		this.collectService = collectService;
		this.footprintService = footprintService;
		this.categoryService = categoryService;
		this.searchHistoryService = searchHistoryService;
		this.goodsSpecificationService = goodsSpecificationService;
		this.litemallAdService = litemallAdService;
	}

	@Resource
	private RedisTemplate<String, LitemallAd> redisTemplate;

	/**
	 * 池中所保存的线程数，包括空闲线程。
	 */
	private final static int CORE_POOL_SIZE = 7;

	/**
	 * 池中允许的最大线程数。
	 */
	private final static int MAXIMUM_POOL_SIZE = 10;

	/**
	 * 当线程数大于核心线程时，此为终止前多余的空闲线程等待新任务的最长时间1s
	 */
	private final static long KEEP_ALIVE_TIME = 1000;

	/**
	 * 执行前用于保持任务的队列，即任务缓存队列
	 */
	private final static ArrayBlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(2048);

	/**
	 * 拒绝策略，都满的情况下把被拒绝的线程重新执行
	 */
	private final static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();

	private static ThreadPoolExecutor executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, WORK_QUEUE, HANDLER);

	/**
	 * 商品详情
	 * <p>
	 * 用户可以不登录。
	 * 如果用户登录，则记录用户足迹以及返回用户收藏信息。
	 *
	 * @param userId 用户ID
	 * @param id     商品ID
	 * @return 商品详情
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * info: xxx,
	 * userHasCollect: xxx,
	 * issue: xxx,
	 * comment: xxx,
	 * specificationList: xxx,
	 * productList: xxx,
	 * attribute: xxx,
	 * brand: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("detail")
	public Object detail(@LoginUser Integer userId, Integer id) {
		if (id == null) {
			return ResponseUtil.badArgument();
		}
		if (userId == null) {
			return ResponseUtil.unlogin();
		}
		// 记录用户的足迹
		executorService.execute(() -> {
			LitemallFootprint footprint = new LitemallFootprint();
			footprint.setAddTime(LocalDateTime.now());
			footprint.setUserId(userId);
			footprint.setMechanismType(false);
			footprint.setGoodsId(id);
			footprintService.add(footprint);
		});
		// 商品属性
		FutureTask<List> goodsAttributeListTask = new FutureTask<>(() -> goodsAttributeService.queryByGid(id));
		// 商品规格
		FutureTask<Object> objectCallableTask = new FutureTask<>(() -> goodsSpecificationService.getSpecificationVoList(id));
		// 商品规格对应的数量和价格
		FutureTask<List> productListCallableTask = new FutureTask<>(() -> productService.queryByGid(id));
		// 商品问题，这里是一些通用问题
		FutureTask<List> issueCallableTask = new FutureTask<>(() -> goodsIssueService.query());
		// 用户收藏
		FutureTask<Integer> userHasCollectCallableTask = new FutureTask<>(() -> collectService.count(userId, id));

		executorService.submit(goodsAttributeListTask);
		executorService.submit(objectCallableTask);
		executorService.submit(productListCallableTask);
		executorService.submit(issueCallableTask);
		executorService.submit(userHasCollectCallableTask);

		// 商品信息
		LitemallGoods info = goodsService.findById(id);
		Map<String, Object> data = new HashMap<>(16);
		LitemallUser user = userService.findById(userId);
		data.put("mobile", user.getMobile());
		data.put("info", info);
		data.put("brand", null);
		try {
			data.put("userHasCollect", userHasCollectCallableTask.get());
			data.put("issue", issueCallableTask.get());
			data.put("comment", "很好");
			data.put("specificationList", objectCallableTask.get());
			data.put("productList", productListCallableTask.get());
			data.put("attribute", goodsAttributeListTask.get());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return ResponseUtil.ok(data);
	}

	@GetMapping("getMemberType")
	public Object getMemberType(@LoginUser Integer userId) {
		Map<String, Object> data = new HashMap<>(16);
		boolean memberType = false;
		boolean hasLogin = false;

		if (userId != null) {
			hasLogin = true;
			LitemallUser litemallUser = userService.findById(userId);
			if (litemallUser.getMemberType() != null) {
				if (litemallUser.getMemberType()) {
					memberType = true;
				}
			}
		}
		data.put("MemberType", memberType);
		data.put("hasLogin", hasLogin);
		return ResponseUtil.ok(data);
	}

	/**
	 * 商品分类类目
	 * <p>
	 * TODO 可能应该合并到WxCatalogController中
	 *
	 * @param id 分类类目ID
	 * @return 商品分类类目
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * currentCategory: xxx,
	 * parentCategory: xxx,
	 * brotherCategory: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("category")
	public Object category(Integer id) {
		String key = "weChatCategory" + id;
		Map<Object, Object> data = new HashMap<>(16);
		// 缓存存在
		boolean hasKey1 = redisTemplate.hasKey(key);
		if (hasKey1) {
			// 从缓存中取
			Map<Object, Object> data1 = redisTemplate.opsForHash().entries(key);
			return ResponseUtil.ok(data1);
		} else {
			LitemallCategory cate = new LitemallCategory();
			LitemallCategory cateList = categoryService.findById(id);
			if (cateList.getPid() != 0) {
				cate.setId(cateList.getPid());
			} else {
				cate.setId(id);
			}
			cate.setName("全部商品");
			if (id == null) {
				return ResponseUtil.badArgument();
			}
			LitemallCategory cur = categoryService.findById(id);
			LitemallCategory parent;
			List<LitemallCategory> children;

			if (cur.getPid() == 0) {
				parent = cur;
				children = categoryService.queryByPid(cur.getId());
			} else {
				parent = categoryService.findById(cur.getPid());
				children = categoryService.queryByPid(cur.getPid());
			}
			children.add(0, cate);
			data.put("currentCategory", cate);
			data.put("parentCategory", parent);
			data.put("brotherCategory", children);
			// 放入缓存，并设置缓存时间
			redisTemplate.opsForHash().putAll(key, data);
			redisTemplate.expire(key, 25, TimeUnit.MINUTES);
			return ResponseUtil.ok(data);
		}
	}

	/**
	 * 根据条件搜素商品
	 * <p>
	 * 1. 这里的前五个参数都是可选的，甚至都是空
	 * 2. 用户是可选登录，如果登录，则记录用户的搜索关键字
	 *
	 * @param categoryId 分类类目ID
	 * @param brandId    品牌商ID
	 * @param keyword    关键字
	 * @param isNew      是否新品
	 * @param isHot      是否热买
	 * @param userId     用户ID
	 * @param page       分页页数
	 * @param size       分页大小
	 * @param sort       排序方式
	 * @param order      排序类型，顺序或者降序
	 * @return 根据条件搜素的商品详情
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * goodsList: xxx,
	 * filterCategoryList: xxx,
	 * count: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("list")
	public Object list(
		Integer categoryId,
		Integer brandId,
		String keyword,
		Integer isNew,
		Integer isHot,
		@LoginUser Integer userId,
		@RequestParam(value = "page", defaultValue = "1") Integer page,
		@RequestParam(value = "size", defaultValue = "10") Integer size,
		String sort,
		String order) {
		Integer integralId = SystemConfig.getCateIntegral();
		Integer marketId = SystemConfig.getCatePrice();
		List<Integer> list = new ArrayList<>();
		list.add(integralId);
		list.add(marketId);
		String sortWithOrder = SortUtil.goodsSort(sort, order);
		//添加到搜索历史
		if (userId != null && StringUtils.isNotEmpty(keyword)) {
			executorService.execute(() -> {
				LitemallSearchHistory searchHistoryVo = new LitemallSearchHistory();
				searchHistoryVo.setAddTime(LocalDateTime.now());
				searchHistoryVo.setKeyword(keyword);
				searchHistoryVo.setUserId(userId);
				searchHistoryVo.setFrom("wx");
				searchHistoryService.save(searchHistoryVo);
			});
		}
		//查询列表数据
		List<Integer> cateList = getBadLevelCategory();
		List<LitemallGoods> goodsList = goodsService.querySelective(categoryId, brandId, keyword, isHot, isNew, page, size, sortWithOrder, cateList);
		long total = PageInfo.of(goodsList).getTotal();
		//查询弹框信息
		String value = SystemConfig.getShopWord();

		// 查询商品所属类目列表。
		List<Integer> goodsCatIds = goodsService.getCatIds(brandId, keyword, isHot, isNew);
		List<LitemallCategory> categoryList = null;
		if (goodsCatIds.size() != 0) {
			categoryList = categoryService.queryL2ByIds(goodsCatIds,cateList);
		}
		Map<String, Object> data = new HashMap<>(16);
		if (list.contains(categoryId)) {
			List<LitemallCategory> catL1List = categoryService.queryByPid(categoryId);
			List<Integer> cidList = new ArrayList<>(16);
			for (LitemallCategory catL1 : catL1List) {
				cidList.add(catL1.getId());
			}
			List<LitemallGoods> categoryGoods;
			if (cidList.size() == 0) {
				categoryGoods = new ArrayList<>();
			} else {
				categoryGoods = goodsService.queryByCategory(cidList, 0, size);
			}
			goodsList.addAll(categoryGoods);
		}
		data.put("shopWord", value);
		data.put("goodsList", goodsList);
		data.put("filterCategoryList", categoryList);
		data.put("count", total);
		return ResponseUtil.ok(data);
	}

	/**
	 * 查询积分及超市商品
	 * @param categoryId
	 * @param brandId
	 * @param keyword
	 * @param isNew
	 * @param isHot
	 * @param catePrice
	 * @param cId
	 * @param cateCount
	 * @param page
	 * @param size
	 * @param sort
	 * @param order
	 * @return
	 */
	@GetMapping("lists")
	public Object lists(
		Integer categoryId,
		Integer brandId,
		String keyword,
		Integer isNew,
		Integer isHot,
		Integer catePrice,
		Integer cId,
		Integer cateCount,
		@RequestParam(value = "page", defaultValue = "1") Integer page,
		@RequestParam(value = "size", defaultValue = "10") Integer size,
		String sort,
		String order) {
		Integer integralId = SystemConfig.getCateIntegral();
		Integer marketId = SystemConfig.getCatePrice();
		List<Integer> list = new ArrayList<>();
		list.add(integralId);
		list.add(marketId);

		//获取超市id
		Integer shop = SystemConfig.getCatePrice();
		//获取积分id
		Integer inte = SystemConfig.getCateIntegral();
		if(catePrice == 0){
			catePrice = null;
		}
		Integer integral = null;
		Integer price = null;
		if(catePrice != null){
			if(cId.equals(shop)){
				price = catePrice;
			}
			if(cId.equals(inte)){
				integral = catePrice;
			}
		}
		//查询列表数据
		List<LitemallGoodsVo> goodsList = goodsService.querySelectives(categoryId, SystemConfig.getCateGoryL2(), integral, price, cateCount, page, size);
		long total = PageInfo.of(goodsList).getTotal();
		//查询弹框信息
		String value = SystemConfig.getShopWord();

		// 查询商品所属类目列表。
		List<Integer> goodsCatIds = goodsService.getCatIds(brandId, keyword, isHot, isNew);
		List<LitemallCategory> categoryList = null;
		if (goodsCatIds.size() != 0) {
			categoryList = categoryService.queryL2ByIds(goodsCatIds,getBadLevelCategory());
		}
		Map<String, Object> data = new HashMap<>(16);
		if (list.contains(categoryId)) {
			List<LitemallCategory> catL1List = categoryService.queryByPid(categoryId);
			List<Integer> cidList = new ArrayList<>(16);
			for (LitemallCategory catL1 : catL1List) {
				cidList.add(catL1.getId());
			}
			List<LitemallGoodsVo> categoryGoods;
			if (cidList.size() == 0) {
				categoryGoods = new ArrayList<>();
			} else {
				categoryGoods = goodsService.queryByCategorys(cidList, integral, price, cateCount, page, size);
			}
			goodsList.addAll(categoryGoods);
		}
		data.put("shopWord", value);
		data.put("goodsList", goodsList);
		data.put("filterCategoryList", categoryList);
		data.put("count", total);
		return ResponseUtil.ok(data);
	}

	/**
	 * 首页一直下拉的商品
	 * 查询的是积分和爱币的商品
	 * 排序按照商品的添加时间降序
	 * @param page
	 * @param size
	 * @return
	 */
	@GetMapping("/getHot")
	public Object getHot(
		@RequestParam(value = "page", defaultValue = "1") Integer page,
		@RequestParam(value = "size", defaultValue = "10") Integer size){
		List<Integer> list = getBadLevelCategory();
		List<LitemallGoodsVo> goodsList = goodsService.queryByHot(list, page, size);
		long total = PageInfo.of(goodsList).getTotal();
		Map<String,Object> map = new HashMap<>(2);
		map.put("goodsList",goodsList);
		map.put("total",total);
		return ResponseUtil.ok(map);
	}

	private List<Integer> getBadLevelCategory(){
		return new ArrayList<Integer>(){
			{add(SystemConfig.getCateGoryL2());
				add(SystemConfig.getCateDuiHuan());
				add(SystemConfig.getGroup());
			}};
	}

	/**
	 * 新品首发页面的横幅数据
	 * <p>
	 *
	 * @return 新品首发页面的栏目数据
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * bannerInfo: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("new")
	public Object newGoods() {
		String key = "weChatNew";
		// 缓存存在
		boolean hasKey1 = redisTemplate.hasKey(key);
		if (hasKey1) {
			Map<Object, Object> data1 = redisTemplate.opsForHash().entries(key);
			return ResponseUtil.ok(data1);
		} else {
			Map<String, String> bannerInfo = new HashMap<>(16);
			bannerInfo.put("url", "");
			bannerInfo.put("name", SystemConfig.getNewBannerTitle());
			bannerInfo.put("imgUrl", SystemConfig.getNewImageUrl());

			Map<String, Object> data = new HashMap<>(16);
			data.put("bannerInfo", bannerInfo);
			// 放入缓存，并设置缓存时间
			redisTemplate.opsForHash().putAll(key, data);
			redisTemplate.expire(key, 60, TimeUnit.MINUTES);
			return ResponseUtil.ok(data);
		}
	}

	/**
	 * 人气推荐页面的横幅数据
	 * <p>
	 *
	 * @return 人气推荐页面的栏目数据
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * bannerInfo: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("hot")
	public Object hotGoods() {
		String key = "weChatHot";
		// 缓存存在 从缓存中取
		boolean hasKey1 = redisTemplate.hasKey(key);
		if (hasKey1) {
			Map<Object, Object> data1 = redisTemplate.opsForHash().entries(key);
			return ResponseUtil.ok(data1);
		} else {
			Map<String, String> bannerInfo = new HashMap<>(16);
			bannerInfo.put("url", "");
			bannerInfo.put("name", SystemConfig.getHotBannerTitle());
			bannerInfo.put("imgUrl", SystemConfig.getHotImageUrl());
			Map<String, Object> data = new HashMap<>(16);
			data.put("bannerInfo", bannerInfo);
			// 放入缓存，并设置缓存时间
			redisTemplate.opsForHash().putAll(key, data);
			redisTemplate.expire(key, 21, TimeUnit.MINUTES);
			return ResponseUtil.ok(data);
		}
	}

	/**
	 * 商品页面推荐商品
	 *
	 * @return 商品页面推荐商品
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * goodsList: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("related")
	public Object related(Integer id) {
		if (id == null) {
			return ResponseUtil.badArgument();
		}

		LitemallGoods goods = goodsService.findById(id);
		if (goods == null) {
			return ResponseUtil.badArgumentValue();
		}

		// 目前的商品推荐算法仅仅是推荐同类目的其他商品
		int cid = goods.getCategoryId();

		// 查找六个相关商品
		int related = 6;
		List<LitemallGoods> goodsList = goodsService.queryByCategory(cid, 0, related);
		Map<String, Object> data = new HashMap<>(16);
		data.put("goodsList", goodsList);
		return ResponseUtil.ok(data);
	}

	/**
	 * 在售的商品总数
	 *
	 * @return 在售的商品总数
	 * 成功则
	 * {
	 * errno: 0,
	 * errmsg: '成功',
	 * data:
	 * {
	 * goodsCount: xxx
	 * }
	 * }
	 * 失败则 { errno: XXX, errmsg: XXX }
	 */
	@GetMapping("count")
	public Object count() {
		Integer goodsCount = goodsService.queryOnSale();
		Map<String, Object> data = new HashMap<>(1);
		data.put("goodsCount", goodsCount);
		return ResponseUtil.ok(data);
	}

	/**
	 * 通过广告id，查找广告下面的商品ids，把ids找出来后找茬对应的商品信息
	 * @param id 广告id
	 * @return 商品信息
	 */
	@GetMapping("getGoodsByAd")
    public Object getGoodsByAd(Integer id){
        LitemallAd litemallAd =  litemallAdService.findById(id);
        String backUrl = litemallAd.getBackgroundUrl();
        String goodIds = litemallAd.getGoodids();
        if(org.apache.commons.lang.StringUtils.isBlank(goodIds)){
        	return ResponseUtil.fail();
        }
        List<String> goodsIds = Arrays.asList(goodIds.split(","));
        List<Integer> goodsInt = new ArrayList<>();
		for(String str : goodsIds) {
			int i = Integer.parseInt(str);
			goodsInt.add(i);
		}
		List<LitemallGoods> goods = goodsService.findByIds(goodsInt);
		Map<String, Object> data = new HashMap<>(1);
		data.put("goods", goods);
		data.put("backUrl",backUrl);
		return ResponseUtil.ok(data);
	}
}